//!动态数组Vec
///特性及声明方式
///和我们之前接触到的Array不同，Vec具有动态的添加和删除元素的能力，并且能够以O(1)的效率进行随机访问。
/// 同时，对其尾部进行push或者pop操作的效率也是平摊O(1)的。 同时，有一个非常重要的特性（虽然我们编程的时候大部分
/// 都不会考量它）就是，Vec的所有内容项都是生成在堆空间上的，也就是说，你可以轻易的将Vec
/// move出一个栈而不用担心内存拷贝影响执行效率——毕竟只是拷贝的栈上的指针。

///另外的就是，Vec<T>中的泛型T必须是Sized的，也就是说必须在编译的时候就知道存一个内容项需要多少内存。
/// 对于那些在编译时候未知大小的项（函数类型等），我们可以用Box将其包裹，当成一个指针。

use std::{time};



//new
//可以用std::vec::Vec::new()的方式来声明一个Vec。
#[test]
pub fn vec_demo1(){
    let mut v1: Vec<i32> = Vec::new();
    v1.push(23_i32);
    println!("{:?}", v1)
}

//宏声明
//相比调用new函数，Rust提供了一种更加直观便捷的方式声明一个动态数组： vec! 宏。
#[test]
pub fn vec_demo2(){
    let v: Vec<i32> = vec![];
    // 以下语句相当于：
// let mut temp = Vec::new();
// temp.push(1);
// temp.push(2);
// temp.push(3);
// let v = temp;
    let v = vec![1, 2, 3];
    println!("{:?}", v);
    let v = vec![0; 10]; //注意分号，这句话声明了一个 内容为10个0的动态数组
    println!("{:?}", v);
}


//从迭代器生成
//因为Vec实现了FromIterator这个trait，因此，借助collect，我们能将任意一个迭代器转换为Vec。
#[test]
pub fn vec_demo3(){
    let v: Vec<i32> = (1..5).collect();
    println!("{:?}", v);
}

//访问及修改
//随机访问
//就像数组一样，因为Vec借助Index和IndexMut提供了随机访问的能力，我们通过[index]来对其进行访问，
// 当然，既然存在随机访问就会出现越界的问题。而在Rust中，一旦越界的后果是极其严重的，可以导致Rust当前线程panic。
// 因此，除非你确定自己在干什么或者在for循环中，不然我们不推荐通过下标访问。

#[test]
pub fn vec_demo4(){
    //创建空集合
    //let v: Vec<i32> = Vec::new();

    let mut v = vec![1, 2, 3];//使用宏创建
    v.push(4);

    //通过索引获取，越界会导致程序panic
    let third: i32 = v[2];
    let second: &i32 = &(v[1]); //使用引用
    println!("third: {}", third);
    println!("second: {}", second);



    //通过get获取,越界不会panic
    match v.get(8){
        Some(value) => {println!("{}", value);},
        None =>{println!("获取失败")},

    }

}

//迭代器,对于一个可变数组，Rust提供了一种简单的遍历形式—— for 循环。 我们可以获得一个数组的引用、可变引用、所有权。

#[test]
pub fn vec_demo5(){
    let mut v = vec![1, 2, 3];
    //每个值都加50
    for i in &mut v{
        *i += 50;
    }
    //遍历
    for num in &v {
        println!("{}", num);
    }
    // 获得所有权，注意此时Vec的属主将会被转移！！
    for i in v {
        println!("{}", i);
    }
}

//push的效率研究
//Vec有两个O(1)的方法，分别是pop和push，它们分别代表着将数据从尾部弹出或者装入。
// 理论上来说，因为Vec是支持随机访问的，因此push效率应该是一致的。但是实际上，因为Vec的内部存在着内存拷贝和销毁，
// 因此，如果你想要将一个数组，从零个元素开始，一个一个的填充直到最后生成一个非常巨大的数组的话，预先为其分配内存
// 是一个非常好的办法。
//这其中，有个关键的方法是reserve。
fn push_1m(v: &mut Vec<usize>, total: usize) {
    let e = time::SystemTime::now();
    for i in 1..total {
        v.push(i);
    }
    let ed = time::SystemTime::now();
    println!("time spend: {:?}", ed.duration_since(e).unwrap());
}
#[test]
pub fn vec_demo6(){
    let mut v: Vec<usize> = vec![];
    push_1m(&mut v, 5_000_000);

    let mut v: Vec<usize> = vec![];
    //预先分配好内存，效率更高
    v.reserve(5_000_000);
    push_1m(&mut v, 5_000_000);
}

#[derive(Debug)]
struct User{
    id: i32,
    name: String,
}
impl Drop for User{
    fn drop(&mut self) {
       println!("Dropping User id={}!", self.id);
    }
}

#[test]
pub fn vec_demo7(){

    let mut v: Vec<User> = vec![User{id:1, name:String::from("李斯")}, 
    User{id:2, name:String::from("赵高")},
    User{id:3, name:String::from("高渐离")}];
    let o = v.get(9);
    match o {
        Some(u) => {println!("{:?}", u)},
        None =>{println!("元素index={}不存在", 9)}
    }

    // 没有实现Copy trait 不能通过下标获取元素
    //let u = v[0];
    //可以获取引用
    let u = &v[0]; 
    println!("{:?}", u);

    //可变引用
    let u = &mut v[0]; 
    u.id = 34;
    u.name = String::from("嬴政");
    println!("{:?}", u);

}

#[test]
pub fn vec_demo8(){
    let mut v: Vec<User>  = vec![];
    v.push(User{id:1, name: String::from("张三")});
    v.push(User{id:2, name: String::from("李四")});
    {
        let o = v.pop();
        match o {
            Some(u) => {println!("pop user id={}", u.id)},
            None=>{}
        }
    }
    println!("ok")
    
}